#ifndef __V4_H__
#define __V4_H__

#include <string>
using namespace std;

#include <dalelib/maths/mathsstuff.h>
#include <dalelib/maths/v2.h>
#include <dalelib/maths/v3.h>

namespace dalelib
{

class v3;

class v4
{
private:

	float f[4];

public:

	/*** constructors ***/
	v4();
	v4(const float _Value);
	v4(const float _Value0, const float _Value1, const float _Value2, const float _Value3);
	static const v4 zero;
	static const v4 one;

	/*** accessors ***/
	const v4 operator =(const v4& _Value);
	float& x() { return f[0]; }
	float& y() { return f[1]; }
	float& z() { return f[2]; }
	float& w() { return f[3]; }
	float& operator[](const int _Index) { return f[_Index]; }
	float* ptr() { return &f[0]; }
	const float& x() const { return f[0]; }
	const float& y() const { return f[1]; }
	const float& z() const { return f[2]; }
	const float& w() const { return f[3]; }
	const float& operator[](const int _Index) const { return f[_Index]; }
	const float* ptr() const { return &f[0]; }

	/*** unary operation ***/
	v4 operator-() const;

	/*** scalar operations ***/
	void operator+=(const float _Value);
	void operator-=(const float _Value);
	void operator*=(const float _Value);
	void operator/=(const float _Value);

	v4 operator+(const float _Value) const;
	v4 operator-(const float _Value) const;
	v4 operator*(const float _Value) const;
	v4 operator/(const float _Value) const;

	/*** vector operations ***/
	void operator+=(const v4& _Value);
	void operator-=(const v4& _Value);
	void operator*=(const v4& _Value);
	void operator/=(const v4& _Value);

	v4 operator+(const v4& _Value) const;
	v4 operator-(const v4& _Value) const;
	v4 operator*(const v4& _Value) const;
	v4 operator/(const v4& _Value) const;

	float len() const;
	float len2() const;
	v4 unit() const;
	void normalise();
	v4 canonicalise();
	v4 recip() const;
	void clamp(const v4& _Min,const v4& _Max);

	static v4 min(const v4& _V1,const v4& _V2) { return v4(mymin(_V1[0],_V2[0]),mymin(_V1[1],_V2[1]),mymin(_V1[2],_V2[2]),mymin(_V1[3],_V2[3])); }
	static v4 max(const v4& _V1,const v4& _V2) { return v4(mymax(_V1[0],_V2[0]),mymax(_V1[1],_V2[1]),mymax(_V1[2],_V2[2]),mymax(_V1[3],_V2[3])); }

	static float dot(const v4 _Value1,const v4 _Value2) { return _Value1[0]*_Value2[0] + _Value1[1]*_Value2[1] + _Value1[2]*_Value2[2] + _Value1[3]*_Value2[3]; }
	void print(string _String="") const;
	void print(string _String="");

	/*** swizzling ***/
	v2 xy() const;
	v2 yz() const;
	v2 xz() const;
	v3 xyz() const;

};

} // namespace dalelib

#endif
